#!/usr/bin/python
# -*- coding: utf-8 -*-

#-------------------------------------------------
#Create At: 2008-7-15 下午11:26:04 
#Create By: Fla.sam
#
#DESC: 
#
#-------------------------------------------------

from mutagen import apev2, flac, mp3, easyid3, id3
import locale
import os
import re
import sys
import threading
import types
import wx

reload( sys )
sys.setdefaultencoding( 'utf8' ) #@UndefinedVariable

MEDIA_ROOT = r'''d:\\Music\\'''

music_mp3_re = re.compile( r'\.([mM][pP][3])$' )
music_apl_re = re.compile( r'\.([aA][pP][lL])$' )
music_cue_re = re.compile( r'\.([cC][uU][eE])$' )
music_ape_re = re.compile( r'\.([aA][pP][eE])$' )
music_flac_re = re.compile( r'\.([fF][lL][aA][cC])$' )

mkapl_exec = 'scripts/MakeAPL.exe'

def get_file_list( p ):
    
    music_files = []
    
    for root, dirs, files in os.walk( p, topdown=False ):
        for name in files:
            f = os.path.join( p, root, name )
            e = os.path.splitext( os.path.basename( f ) )[1]
            # filter all flac files
            if music_flac_re.search( e ):
                music_files.append( ( f, 'flac' ) )
            
            # filter all mp3 files
            if music_mp3_re.search( e ):
                music_files.append( ( f, 'mp3' ) )
                
            # filter all apl files
            if music_apl_re.search( e ):
                music_files.append( ( f, 'apl' ) )
                
            # filter all ape files
            if music_ape_re.search( e ):
                music_files.append( ( f, 'ape' ) ) 
            
        for name in dirs:
            pass 
    return music_files
        

class ReadTag:
    
    def __init__( self , music_lists ):
        
        self.music_tags = []
        
        self.mp3_channel_mode = {0:'STEREO', 1:'JOINTSTEREO', 2:'DUALCHANNEL', 3:'MONO'}
        self.flac_channel_mode = {1:'MONO', 2:'STEREO'}

        self.music_lists = music_lists
        self.count = len( self.music_lists )
        self.index = self.count
        
    def cover_bitrate( self, bi ):
        return '%dKb' % int( bi / 1000 )
    
    def cover_samplerate( self, sa ):
        return '%.1FHz' % ( float( sa ) / 1000 )
    
    def cover_length( self, le ):
        return '%dm%ds' % ( int( le / 60 ), ( le / 60 - int( le / 60 ) ) * 60 )
    
#    def cover_size(self, si):
#        return '%.1FKB' % ( float( si )/1000 )

    def cover_size( self, si ):
        byteCount = si
        if byteCount < 0:
            return ""

        for ( cutoff, label ) in [( 1024 * 1024 * 1024, "GB" ), ( 1024 * 1024, "MB" ), ( 1024, "KB" )]:
            if byteCount >= cutoff:
                return "%.1f%s" % ( byteCount * 1.0 / cutoff, label )

        if byteCount == 1:
            return "1B"
        else:
            return "%dB" % byteCount
        
    def __read_mp3_type( self, f ):
        try:
            audio = mp3.MP3( f, ID3=easyid3.EasyID3 )
            a = {}
            try: a['title'] = audio['title'][0] ; 
            except: a['title'] = os.path.basename( f );
                
            try: a['album'] = audio['album'][0];
            except :a['album'] = u'unknow';
                
            try: a['artist'] = audio['artist'][0];
            except: a['artist'] = u'unknow';
                
            try: a['tracknumber'] = audio['tracknumber'][0]
            except: a['tracknumber'] = u'unknow';
                
            try: a['genre'] = audio['genre'][0];
            except: a['genre'] = u'unknow';
            
            try: a['date'] = audio['date'][0];
            except: a['date'] = u'unknow';
            
            try: a['bitrate'] = self.cover_bitrate( audio.info.bitrate );
            except: a['bitrate'] = u'unknow';
            
            try: a['samplerate'] = self.cover_samplerate( audio.info.sample_rate );
            except: a['samplerate'] = u'unknow';
            
            try: a['length'] = self.cover_length( audio.info.length );
            except: a['length'] = u'unknow';
            
            try: a['channel'] = self.mp3_channel_mode[audio.info.mode];
            except: a['channel'] = u'unknow';
            
            try: a['size'] = self.cover_size( os.path.getsize( f ) );
            except: a['size'] = u'unknow';

            return {f: ( a, 'mp3' )}
        
        except mp3.HeaderNotFoundError: return {f: ( None, 'mp3' ) }
        except mp3.InvalidMPEGHeader: return {f: ( None, 'mp3' ) }
        except id3.ID3NoHeaderError: return {f: ( None, 'mp3' ) }
        except id3.ID3BadUnsynchData: return {f: ( None, 'mp3' ) }
        except id3.ID3BadCompressedData: return {f: ( None, 'mp3' ) }
        except id3.ID3TagError: return {f: ( None, 'mp3' ) }
        except id3.ID3UnsupportedVersionError: return {f: ( None, 'mp3' ) }
        except id3.ID3EncryptionUnsupportedError: return {f: ( None, 'mp3' ) }
        except id3.ID3JunkFrameError : return {f: ( None, 'mp3' ) }
        except : return {f: ( None, 'mp3' ) }
        else: return {f: ( None, 'mp3' ) }

    def __read_apl_type( self, f ):
        try:
            audio = apev2.APEv2( f )
            #['Track', 'Album', 'Title', 'Artist']
            #['Album', 'Comment', 'Title', 'Artist', 'Year', 'Genre']
            a = {}
            try: a['title'] = audio['Title'][0] ; 
            except: a['title'] = os.path.basename( f );
                
            try: a['album'] = audio['Album'][0];
            except :a['album'] = u'unknow';
                
            try: a['artist'] = audio['Artist'][0];
            except: a['artist'] = u'unknow';
                
            try: a['tracknumber'] = audio['Track'][0]
            except: a['tracknumber'] = u'unknow';
                
            try: a['genre'] = audio['Genre'][0];
            except: a['genre'] = u'unknow';
            
            try: a['date'] = audio['Year'][0];
            except: a['date'] = u'unknow';
            
            a['bitrate'] = u'unknow';
            
            a['samplerate'] = u'unknow';
            
            a['length'] = u'unknow';
            
            a['channel'] = u'unknow';

            try: a['size'] = self.cover_size( os.path.getsize( f ) );
            except: a['size'] = u'unknow';

            return {f: ( a, 'apl' ) }
        
        except apev2.APENoHeaderError: return {f:( None, 'apl' )}
        except apev2.APEBadItemError: return {f:( None, 'apl' )}
        except apev2.APEUnsupportedVersionError: return {f:( None, 'apl' )}
        else: return {f:( None, 'apl' )}
        
    def __read_flac_type( self, f ):
        try:
            audio = flac.FLAC( f )
            a = {}
            try: a['title'] = audio['title'][0] ; 
            except: a['title'] = os.path.basename( f );
                
            try: a['album'] = audio['album'][0];
            except :a['album'] = u'unknow';
                
            try: a['artist'] = audio['artist'][0];
            except: a['artist'] = u'unknow';
                
            try: a['tracknumber'] = audio['tracknumber'][0]
            except: a['tracknumber'] = u'unknow';
                
            try: a['genre'] = audio['genre'][0];
            except: a['genre'] = u'unknow';
            
            try: a['date'] = audio['date'][0];
            except: a['date'] = u'unknow';
            
            try: a['bitrate'] = self.cover_bitrate( audio.info.total_samples );
            except: a['bitrate'] = u'unknow';
            
            try: a['samplerate'] = self.cover_samplerate( audio.info.sample_rate );
            except: a['samplerate'] = u'unknow';
            
            try: a['length'] = self.cover_length( audio.info.length );
            except: a['length'] = u'unknow';
            
            try: a['channel'] = self.flac_channel_mode[audio.info.channels];
            except: a['channel'] = u'unknow';

            try: a['size'] = self.cover_size( os.path.getsize( f ) );
            except: a['size'] = u'unknow';
            
            return {f:( a, 'flac' )}
        
        except flac.FLACNoHeaderError: return {f:( None, 'flac' )}
        except flac.FLACVorbisError: return {f:( None, 'flac' )}
        except: return {f:( None, 'flac' )}
        else: return {f:( None, 'flac' )}

    def __read_ape_type( self, f ):
        try:
            audio = apev2.APEv2( f )
            #['Album', 'Comment', 'Title', 'Artist', 'Year', 'Genre']
            a = {}
            try: a['title'] = audio['Title'][0] ; 
            except: a['title'] = os.path.basename( f );
                
            try: a['album'] = audio['Album'][0];
            except :a['album'] = u'unknow';
                
            try: a['artist'] = audio['Artist'][0];
            except: a['artist'] = u'unknow';
                
            try: a['tracknumber'] = audio['Track'][0]
            except: a['tracknumber'] = u'unknow';
                
            try: a['genre'] = audio['Genre'][0];
            except: a['genre'] = u'unknow';
            
            try: a['date'] = audio['Year'][0];
            except: a['date'] = u'unknow';
            
            a['bitrate'] = u'unknow';
            
            a['samplerate'] = u'unknow';
            
            a['length'] = u'unknow';
            
            a['channel'] = u'unknow';
            
            try: a['size'] = self.cover_size( os.path.getsize( f ) );
            except: a['size'] = u'unknow';

            return {f:( a, 'ape' )}
        
        except apev2.APENoHeaderError: return {f:( None, 'ape' )}
        except apev2.APEBadItemError: return {f:( None, 'ape' )}
        except apev2.APEUnsupportedVersionError: return {f:( None, 'ape' )}
        except: return {f:( None, 'ape' )}
        else: return {f:( None, 'ape' )}
        
    def get_all_files_tag( self ):
        self.music_tags.reverse()
        return self.music_tags

    def __len__( self ):
        return self.count
    
    def __iter__( self ):
        return self
    
    def next( self ):
        if self.index == 0:
            raise StopIteration
        self.index -= 1
        fi, ty = self.music_lists[self.index]
        if ty == 'mp3':
            _t = self.__read_mp3_type( fi )
        elif ty == 'flac':
            _t = self.__read_flac_type( fi )
        elif ty == 'apl':
            _t = self.__read_apl_type( fi )
        elif ty == 'ape':
            _t = self.__read_ape_type( fi )
        else:
            _t = {fi: ( None, ty )}
        self.music_tags.append( Track( _t ) )
        return _t
    
class Tag( object ):
    
    def __init__( self, track_obj ):
        self.__track_obj = track_obj
        self.filepath = self.__track_obj.filepath
        self.ape_tag = apev2.APEv2( self.filepath )
        self.id3_tag = mp3.MP3( self.filepath, ID3=easyid3.EasyID3 )
        if self.track_obj.file_type == 'flac':
            self.flac_tag = flac.FLAC( self.filepath )
        
    
    def get_APE_tag( self ):
        pass
    
    def get_ID3v2_tag( self ):
        pass
    
    def get_ID3v1_tag( self ):
        pass
    
    def save( self ):
        pass
    
class Track( object ):
    
    def __init__( self, item ):
        self.__item = item
        self.filepath, self.__info = self.__item.items()[0]
        
        #self.filepath = unicode(self.filepath,'cp936').encode('utf8')
        self.filepath = self.__fix_code( self.filepath )
        self.__info, self.file_type = self.__info
        #print self.__item
        
        if self.__info != None:
            self.artist = self.__fix_code( self.__info['artist'] )
            self.title = self.__fix_code( self.__info['title'] )
            self.album = self.__fix_code( self.__info['album'] )
            self.date = self.__fix_code( self.__info['date'] )
            self.genre = self.__fix_code( self.__info['genre'] )
            self.bitrate = self.__fix_code( self.__info['bitrate'] )
            self.samplerate = self.__fix_code( self.__info['samplerate'] )
            self.channel = self.__fix_code( self.__info['channel'] )
            self.length = self.__fix_code( self.__info['length'] )
            self.size = self.__fix_code( self.__info['size'] )
            self.tracknumber = self.__fix_code( self.__info['tracknumber'] )
        else:
            self.artist = u'unknow'
            self.title = u'unknow'
            self.album = u'unknow'
            self.date = u'unknow'
            self.genre = u'unknow'
            self.bitrate = u'unknow'
            self.samplerate = u'unknow'
            self.channel = u'unknow'
            self.length = u'unknow'
            self.size = u'unknow'
            self.tracknumber = u'unknow'
            
        self.bitrate_samplerate_channel = u'%s/%s/%s' % ( self.bitrate, self.samplerate, self.channel )
            
        #print self.title, self.artist, self.album, self.date, self.genre, self.bitrate, self.samplerate, self.channel, self.length, self.size
        #print self.title.__class__, self.filepath.__class__, self.filepath
        
    def __fix_code( self, s ):
        if not isinstance( s, types.UnicodeType ):
            return unicode( s, 'gbk' )
        else:
            return s

        
def load_music_list():
    
    a = get_file_list( MEDIA_ROOT )
    s = ReadTag( a )
    #s.get_file_list(MEDIA_ROOT)
    
    for x in s:
        pass
    
    return s.get_all_files_tag()
    
    #threading.Thread(target=ReadTag, args=(MEDIA_ROOT,)).start()

def make_apl( p ):
    import subprocess
    a = get_file_list( p )
    for fi, ty in a:
        if ty == 'cue':
            print 'make apl file %s' % fi
            subprocess.call( [mkapl_exec, fi] )

if __name__ == '__main__':
    load_music_list()
    #make_apl(MEDIA_ROOT)
#    import xiami_utils
#    
#    a = xiami_utils.__XiaMiWebSearchHelper()